package com.lp.article.listener;

import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.lp.article.mapper.*;
import com.lp.article.service.ILikeService;
import com.lp.model.config.AppResult;
import com.lp.model.config.CodeMsg;
import com.lp.model.constants.MQConstants;
import com.lp.model.constants.RedisConstants;
import com.lp.model.entity.article.Article;
import com.lp.model.entity.article.redis.LikesMsg;
import com.lp.model.exception.ApplicationException;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.core.StringRedisTemplate;

import java.util.Date;
import java.util.HashMap;

@Slf4j
@Configuration
public class LikeListener {

    @Autowired
    private ObjectMapper objectMapper;

    @Autowired
    private StringRedisTemplate redisTemplate;

    @Autowired
    private LikesMapper likesMapper;

    @Autowired
    private ArticleStatMapper articleStatMapper;

    @Autowired
    private ArticleMapper articleMapper;

    @Autowired
    private ILikeService likeService;

    /**
     * 点赞消息
     * @param msg userId 和 articleId
     */
    @SneakyThrows
    @RabbitListener(queues = MQConstants.ARTICLE_LIKE_QUEUE)
    public void articleLikeMsg(String msg) {
        log.info("MQ 消息: 点赞/取消 消息 {}", msg);
        //1.解析数据
        HashMap hashMap = objectMapper.readValue(msg, HashMap.class);
        Long userId = objectMapper.convertValue(hashMap.get("userId"),
                new TypeReference<Long>() {});
        Long articleId = objectMapper.convertValue(hashMap.get("articleId"),
                new TypeReference<Long>() {});
        //2.检查 redis 上是否存在点赞数据，同时将状态更新到 MySQL 上
        if(Boolean.TRUE.equals(redisTemplate.opsForSet().isMember(RedisConstants.ARTICLE_LIKE + articleId,
                RedisConstants.ARTICLE_LIKE_VALUE + userId))) {
            //1) 存在表示: 已点赞，那么现在就要删除点赞信息
            redisTemplate.opsForSet().remove(RedisConstants.ARTICLE_LIKE + articleId,
                    RedisConstants.ARTICLE_LIKE_VALUE + userId);
            likesMapper.remove(articleId, userId);
            articleStatMapper.likeIncrOrDecr(articleId, -1);
            log.info("用户 {} 对文章 {} 取消点赞！", userId, articleId);
        } else {
            //2) 不存在表示: 未点赞，那么现在就要增加点赞信息
            redisTemplate.opsForSet().add(RedisConstants.ARTICLE_LIKE + articleId,
                    RedisConstants.ARTICLE_LIKE_VALUE + userId);
            likesMapper.add(articleId, userId);
            articleStatMapper.likeIncrOrDecr(articleId, +1);
            log.info("用户 {} 对文章 {} 点赞！", userId, articleId);
            //3) 点赞消息 和 状态 处理
            handlerLikeMsgAndState(userId, articleId);
        }
        log.info("MQ 完成: 点赞数据同步到 redis 和 mysql");
    }

    /**
     * 处理点赞消息和状态
     * @param fromId 谁给这篇文章点的赞
     * @param postId 给那篇文章点的赞
     */
    private void handlerLikeMsgAndState(Long fromId, Long postId) {
        //1.获取这篇文章的作者id
        Article article = articleMapper.selectArticleById(postId);
        if(article == null) {
            throw new ApplicationException(AppResult.fail(CodeMsg.FAIL_ERROR_ARTICLE_ID));
        }
        Long userId = article.getUserId();
        //2.添加点赞消息
        likeService.addMsg(new LikesMsg(userId, fromId, postId, new Date()));
    }

}
